import { Token } from "@/utils/cache";

type HeartBeat =
  | false
  | {
      duration?: number;
      sendValue?: any;
    };
type Event = "open" | "close" | "message" | "reconnect" | "error";

export interface SocketProps {
  heartBeat?: HeartBeat;
  maxConnectCount?: number;
  reconnectTime?: number;
}
export default class Socket {
  private _url: string;
  private _handClose: boolean = false;
  private _options: SocketProps;
  private _on = new Map<Event, Array<Function>>();
  private _reconnectTimer: number = 0;
  private socket: any;

  private _connectCount: number = 0;
  constructor(
    url: string,
    options: SocketProps = { maxConnectCount: 10, reconnectTime: 5000 }
  ) {
    this._url = url;
    this._options = options;
  }
  connect() {
    this.socket = uni.connectSocket({
      url: this._url,
      header: {
        token: Token.get()
      },
      complete: () => {}
    });

    const broadCast = (event: Event, value?: any) => {
      const eventList = this._on.get(event);
      if (eventList?.length) {
        for (let i = 0; i < eventList.length; i++) {
          eventList[i](value);
        }
      }
    };

    this.socket.onOpen((res: any) => {
      console.log("连接成功", res);
      broadCast("open", res);
      this._handClose = false;
      // 是否发送心跳
      if (this._options.heartBeat) {
        const { duration, sendValue } = this._options.heartBeat;
        let timer = 0;
        const sendHeart = () => {
          if (this.socket?.readyState === this.socket.OPEN) {
            timer = setTimeout(() => {
              this.send(sendValue);
              sendHeart();
            }, duration);
          } else {
            clearTimeout(timer);
          }
        };
        sendHeart();
      }
    });

    this.socket.onMessage((message: any) => {
      console.log("获取消息");
      const data = JSON.parse(message.data);

      broadCast("message", data);
    });

    const reconnect = () => {
      if (
        this.socket.readyState !== this.socket.CLOSED ||
        this._connectCount > this._options.maxConnectCount!
      ) {
        clearTimeout(this._reconnectTimer);
        this._handClose = false;
        return;
      }
      this._reconnectTimer = setTimeout(() => {
        this._connectCount++;
        this.connect();
      }, this._options.reconnectTime);
    };

    this.socket.onClose(() => {
      console.log("连接关闭", this.socket);
      broadCast("close");
      // 非手动关闭
      if (!this._handClose) {
        reconnect();
      }
    });

    this.socket.onError((error: any) => {
      console.log("连接关闭");
      broadCast("error", error);
    });
  }

  close() {
    this._handClose = true;
    if (this.socket) {
      this.socket.close();
    }
  }
  on(event: Event, callback: Function) {
    if (this._on.has(event)) {
      const callbacks = this._on.get(event) as Array<Function>;
      callbacks.push(callback);
      this._on.set(event, callbacks);
    } else {
      this._on.set(event, [callback]);
    }
  }
  send(value: any) {
    if (this.socket) {
      this.socket.send({
        data: JSON.stringify(value)
      });
    }
  }
}
